home *** CD-ROM | disk | FTP | other *** search
/ Aminet 24 / Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso / Aminet / comm / mail / Mutt089src.lha / Mutt-0.89i-AMIGA / src / keymap.c < prev    next >
C/C++ Source or Header  |  1998-01-28  |  11KB  |  447 lines

  1. /*
  2.  * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
  3.  * 
  4.  *     This program is free software; you can redistribute it and/or modify
  5.  *     it under the terms of the GNU General Public License as published by
  6.  *     the Free Software Foundation; either version 2 of the License, or
  7.  *     (at your option) any later version.
  8.  * 
  9.  *     This program is distributed in the hope that it will be useful,
  10.  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *     GNU General Public License for more details.
  13.  * 
  14.  *     You should have received a copy of the GNU General Public License
  15.  *     along with this program; if not, write to the Free Software
  16.  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  */ 
  18.  
  19. #include "mutt.h"
  20. #include "mutt_curses.h"
  21. #include "keymap.h"
  22. #include "mapping.h"
  23.  
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <ctype.h>
  27.  
  28. #include "functions.h"
  29.  
  30. /* contains the last key the user pressed */
  31. int LastKey;
  32.  
  33. struct keymap_t *Keymaps[MENU_MAX];
  34.  
  35. static struct keymap_t *allocKeys (int len, keycode_t *keys)
  36. {
  37.   struct keymap_t *p;
  38.  
  39.   p = safe_calloc (1, sizeof (struct keymap_t));
  40.   p->len = len;
  41.   p->keys = safe_malloc (len * sizeof (keycode_t));
  42.   memcpy (p->keys, keys, len * sizeof (keycode_t));
  43.   return (p);
  44. }
  45.  
  46. static struct mapping_t KeyNames[] = {
  47.   { "pageup",    KEY_PPAGE },
  48.   { "pagedown",    KEY_NPAGE },
  49.   { "up",    KEY_UP },
  50.   { "down",    KEY_DOWN },
  51.   { "right",    KEY_RIGHT },
  52.   { "left",    KEY_LEFT },
  53.   { "delete",    KEY_DC },
  54.   { "backspace",KEY_BACKSPACE },
  55.   { "insert",    KEY_IC },
  56.   { "home",    KEY_HOME },
  57.   { "end",    KEY_END },
  58.   { "enter",    KEY_ENTER },
  59.   { "return",    M_ENTER_C },
  60.   { NULL,    0 }
  61. };
  62.  
  63. static int parsekeys (char *s, keycode_t *d, int max)
  64. {
  65.   int n, len = max;
  66.  
  67.   while (*s && len)
  68.   {
  69.     if ((n = mutt_getvaluebyname (s, KeyNames)) != -1)
  70.     {
  71.       s += strlen (s);
  72.       *d = n;
  73.     }
  74.     else if (tolower (*s) == 'f' && isdigit (*(s + 1)))
  75.     {
  76.       n = 0;
  77.       for (s++ ; isdigit (*s) ; s++)
  78.       {
  79.     n *= 10;
  80.     n += *s - '0';
  81.       }
  82.       *d = KEY_F(n);
  83.     }
  84.     else
  85.     {
  86.       *d = *s;
  87.       s++;
  88.     }
  89.     d++;
  90.     len--;
  91.   }
  92.  
  93.   return (max - len);
  94. }
  95.  
  96. /* insert a key sequence into the specified map.  the map is sorted by ASCII
  97.  * value (lowest to highest)
  98.  */
  99. void km_bindkey (char *s, int menu, int op, char *macro)
  100. {
  101.   struct keymap_t *map, *tmp, *last = NULL, *next;
  102.   keycode_t buf[MAX_SEQ];
  103.   int len, pos = 0, lastpos = 0;
  104.  
  105.   len = parsekeys (s, buf, MAX_SEQ);
  106.  
  107.   map = allocKeys (len, buf);
  108.   map->op = op;
  109.   map->macro = safe_strdup (macro);
  110.  
  111.   tmp = Keymaps[menu];
  112.  
  113.   while (tmp)
  114.   {
  115.     if (pos >= len || pos >= tmp->len)
  116.     {
  117.       /* map and tmp match, but have different lengths, so overwrite */
  118.       do
  119.       {
  120.     len = tmp->eq;
  121.     next = tmp->next;
  122.     if (tmp->macro)
  123.       free (tmp->macro);
  124.     free (tmp->keys);
  125.     free (tmp);
  126.     tmp = next;
  127.       }
  128.       while (tmp && len >= pos);
  129.       map->eq = len;
  130.       break;
  131.     }
  132.     else if (buf[pos] == tmp->keys[pos])
  133.       pos++;
  134.     else if (buf[pos] < tmp->keys[pos])
  135.     {
  136.       /* found location to insert between last and tmp */
  137.       map->eq = pos;
  138.       break;
  139.     }
  140.     else /* buf[pos] > tmp->keys[pos] */
  141.     {
  142.       last = tmp;
  143.       lastpos = pos;
  144.       if (pos > tmp->eq)
  145.     pos = tmp->eq;
  146.       tmp = tmp->next;
  147.     }
  148.   }
  149.  
  150.   map->next = tmp;
  151.   if (last)
  152.   {
  153.     last->next = map;
  154.     last->eq = lastpos;
  155.   }
  156.   else
  157.     Keymaps[menu] = map;
  158. }
  159.  
  160. static void push_string (char *s)
  161. {
  162.   char *p = s + strlen (s) - 1;
  163.  
  164.   while (p >= s)
  165.     mutt_ungetch (*p--);
  166. }
  167.  
  168. static int retry_generic (int menu, keycode_t *keys, int keyslen, int lastkey)
  169. {
  170.   if (menu != MENU_EDITOR && menu != MENU_GENERIC && menu != MENU_PAGER)
  171.   {
  172.     if (lastkey)
  173.       mutt_ungetch (lastkey);
  174.     for (; keyslen; keyslen--)
  175.       mutt_ungetch (keys[keyslen - 1]);
  176.     return (km_dokey (MENU_GENERIC));
  177.   }
  178.   if (menu != MENU_EDITOR)
  179.   {
  180.     /* probably a good idea to flush input here so we can abort macros */
  181.     mutt_flushinp ();
  182.   }
  183.   return OP_NULL;
  184. }
  185.  
  186. /* return values:
  187.  *    >0        function to execute
  188.  *    OP_NULL        no function bound to key sequence
  189.  *    -1        error occured while reading input
  190.  */
  191. int km_dokey (int menu)
  192. {
  193.   struct keymap_t *map = Keymaps[menu];
  194.   int pos = 0;
  195.   int n = 0;
  196.  
  197.   if (!map)
  198.     return (retry_generic (menu, NULL, 0, 0));
  199.  
  200.   FOREVER
  201.   {
  202.     if ((LastKey = mutt_getch ()) == ERR)
  203.       return (-1);
  204.  
  205.     while (LastKey > map->keys[pos])
  206.     {
  207.       if (pos > map->eq || !map->next)
  208.     return (retry_generic (menu, map->keys, pos, LastKey));
  209.       map = map->next;
  210.     }
  211.  
  212.     if (LastKey != map->keys[pos])
  213.       return (retry_generic (menu, map->keys, pos, LastKey));
  214.  
  215.     if (++pos == map->len)
  216.     {
  217.       if (map->op != OP_MACRO)
  218.     return (map->op);
  219.  
  220.       if (n++ == 10)
  221.       {
  222.     mutt_flushinp ();
  223.     mutt_error ("Macro loop detected.");
  224.     return (-1);
  225.       }
  226.  
  227.       push_string (map->macro);
  228.       map = Keymaps[menu];
  229.       pos = 0;
  230.     }
  231.   }
  232.  
  233.   /* not reached */
  234. }
  235.  
  236. static void create_bindings (struct binding_t *map, int menu)
  237. {
  238.   int i;
  239.  
  240.   for (i = 0 ; map[i].name ; i++)
  241.     if (map[i].seq)
  242.       km_bindkey (map[i].seq, menu, map[i].op, NULL);
  243. }
  244.  
  245. char *km_keyname (int c)
  246. {
  247.   static char buf[5];
  248.  
  249.   switch (c)
  250.   {
  251.     case '\033':
  252.       return "ESC";
  253.     case ' ':
  254.       return "SPC";
  255.     case '\n':
  256.     case '\r':
  257.       return "RET";
  258.     case '\t':
  259.       return "TAB";
  260.     case KEY_UP:
  261.       return "Up";
  262.     case KEY_DOWN:
  263.       return "Down";
  264.     case KEY_LEFT:
  265.       return "Left";
  266.     case KEY_RIGHT:
  267.       return "Right";
  268.     case KEY_NPAGE:
  269.       return "PageDn";
  270.     case KEY_PPAGE:
  271.       return "PageUp";
  272.     case KEY_BACKSPACE:
  273.       return "BackSpace";
  274.     case KEY_HOME:
  275.       return "Home";
  276.     case KEY_END:
  277.       return "End";
  278.     case KEY_DC:
  279.       return "DEL";
  280.     case KEY_IC:
  281.       return "INS";
  282.   }
  283.  
  284.   if (c < 256 && c > -128 && iscntrl ((unsigned char) c))
  285.   {
  286.     if (c < 0)
  287.       c += 256;
  288.  
  289.     if (c < 128)
  290.     {
  291.       buf[0] = '^';
  292.       buf[1] = (c + '@') & 0x7f;
  293.       buf[2] = 0;
  294.     }
  295.     else
  296.       snprintf (buf, sizeof (buf), "\\%d%d%d", c >> 6, (c >> 3) & 7, c & 7);
  297.   }
  298.   else if (c >= KEY_F0 && c < KEY_F(256)) /* this maximum is just a guess */
  299.     sprintf (buf, "F%d", c - KEY_F0);
  300.   else if (IsPrint (c))
  301.     snprintf (buf, sizeof (buf), "%c", (unsigned char) c);
  302.   else
  303.     snprintf (buf, sizeof (buf), "\\x%hx", (unsigned short) c);
  304.   return (buf);
  305. }
  306.  
  307. int km_expand_key (char *s, size_t len, struct keymap_t *map)
  308. {
  309.   size_t l;
  310.   int p = 0;
  311.  
  312.   if (!map)
  313.     return (0);
  314.  
  315.   FOREVER
  316.   {
  317.     strfcpy (s, km_keyname (map->keys[p]), len);
  318.     len -= (1 + (l = strlen (s)));
  319.  
  320.     if (++p >= map->len || !len)
  321.       return (1);
  322.  
  323.     s += l;
  324.     *(s++) = ' ';
  325.   }
  326.  
  327.   /* not reached */
  328. }
  329.  
  330. struct keymap_t *km_find_func (int menu, int func)
  331. {
  332.   struct keymap_t *map = Keymaps[menu];
  333.  
  334.   for (; map; map = map->next)
  335.     if (map->op == func)
  336.       break;
  337.   return (map);
  338. }
  339.  
  340. void km_init (void)
  341. {
  342.   memset (Keymaps, 0, sizeof (struct keymap_t *) * MENU_MAX);
  343.  
  344.   create_bindings (OpAlias, MENU_ALIAS);
  345.   create_bindings (OpAttach, MENU_ATTACH);
  346.   create_bindings (OpBrowser, MENU_FOLDER);
  347.   create_bindings (OpCompose, MENU_COMPOSE);
  348.   create_bindings (OpMain, MENU_MAIN);
  349.   create_bindings (OpPager, MENU_PAGER);
  350.   create_bindings (OpPost, MENU_POST);
  351. #ifdef _PGPPATH
  352.   create_bindings (OpPgp, MENU_PGP);
  353. #endif
  354.  
  355.   /* bindings for the line editor */
  356.   create_bindings (OpEditor, MENU_EDITOR);
  357.  
  358.   km_bindkey ("up", MENU_EDITOR, OP_EDITOR_HISTORY_UP, NULL);
  359.   km_bindkey ("down", MENU_EDITOR, OP_EDITOR_HISTORY_DOWN, NULL);
  360.   km_bindkey ("left", MENU_EDITOR, OP_EDITOR_BACKWARD_CHAR, NULL);
  361.   km_bindkey ("right", MENU_EDITOR, OP_EDITOR_FORWARD_CHAR, NULL);
  362.   km_bindkey ("home", MENU_EDITOR, OP_EDITOR_BOL, NULL);
  363.   km_bindkey ("end", MENU_EDITOR, OP_EDITOR_EOL, NULL);
  364.   km_bindkey ("backspace", MENU_EDITOR, OP_EDITOR_BACKSPACE, NULL);
  365.   km_bindkey ("delete", MENU_EDITOR, OP_EDITOR_BACKSPACE, NULL);
  366.   km_bindkey ("\177", MENU_EDITOR, OP_EDITOR_BACKSPACE, NULL);
  367.  
  368.   /* generic menu keymap */
  369.   create_bindings (OpGeneric, MENU_GENERIC);
  370.  
  371.   km_bindkey ("home", MENU_GENERIC, OP_FIRST_ENTRY, NULL);
  372.   km_bindkey ("end", MENU_GENER